import { ForbiddenException, Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { JwtService } from '@nestjs/jwt'
import { InjectRepository } from '@nestjs/typeorm'
import { IUser } from 'src/config/constants/IUser'
import { ResultData } from 'src/config/constants/ResultData'
import { ConfigurationKeys } from 'src/config/resources'
import { User } from 'src/entity/User'
import { RedisService } from 'src/shared/redis/redis.service'
import { generateCanvas } from 'src/utils/canvans'
import { encryptAES256CBC } from 'src/utils/crypto'
import { createDate } from 'src/utils/utils'
import { Repository } from 'typeorm'
import { RedisKeyMap } from './user.contants'
import { userLoginDto, userRegisterDto } from './user.dto'

@Injectable()
export class UserService {
  constructor(@InjectRepository(User) private user: Repository<User>,
    private readonly _redis: RedisService,
    private config: ConfigService<ConfigurationKeys>,
    private readonly _jwt: JwtService,) { }


  async userRegister(data: userRegisterDto) {
    const findUser = await this.user.findOneBy({ userName: data.userName })

    if (findUser?.userId) {
      return ResultData.fail({ msg: '用户名已存在' })
    }

    const { encodedPassword, iv } = encryptAES256CBC(data.userPwd, this.config.get('crypto.secret'))

    const insertUser = await this.user.insert({
      userNickname: data.userNickname ?? '默认用户',
      userName: data.userName,
      userPwd: encodedPassword,
      userIv: iv,
      userState: 1,
      userAvatar: data.userAvatar ?? 'http://qiniu.xuanxiaoqian.com/xuanxiaoqian.jpg'
    })


    if (insertUser?.raw?.insertId) {
      return ResultData.ok({ msg: '注册成功' })
    } else {
      throw new ForbiddenException('数据库错误')
    }
  }



  async userLogin(data: userLoginDto, ip: string) {
    const { userName, userPwd, murmur, verificationCode } = data

    const isCode = await this._redis.get(RedisKeyMap.userCode(murmur))

    if (isCode === '') {
      return ResultData.fail({ msg: '验证码过期', data: { image: await this.generateCode(murmur) } })
    }

    if (isCode !== verificationCode.toLowerCase()) {
      return ResultData.fail({ msg: '验证码错误', data: { image: await this.generateCode(murmur) } })
    }

    const userFindOne = await this.user.findOneBy({ userName: userName })
    if (!userFindOne?.userId) {
      return ResultData.fail({ msg: '用户名或密码错误', data: { image: await this.generateCode(murmur) } })
    }

    const { encodedPassword } = encryptAES256CBC(userPwd, this.config.get('crypto.secret'), userFindOne.userIv)

    const validateUser = await this.user.createQueryBuilder('user')
      .select(['user.userId', 'user.userNickname', 'user.userAvatar', 'user.userState'])
      .where('user.userName = :userName', { userName: userName })
      .andWhere('user.userPwd = :userPwd', { userPwd: encodedPassword })
      .getOne()

    if (validateUser?.userId) {
      if (validateUser.userState == 1) {
        validateUser.lastLoginTime = createDate()
        validateUser.lastLoginIp = ip
        await this.user.save(validateUser)
        await this._redis.del(RedisKeyMap.userCode(murmur))

        return ResultData.ok({ msg: '登录成功', data: { ...validateUser, token: this._jwt.sign({ userId: validateUser.userId }) } })
      }

      return ResultData.fail({ msg: '账号已被禁用' })
    }

    return ResultData.fail({ msg: '用户名或密码错误', data: { image: await this.generateCode(murmur) } })
  }

  async getUserData(data: IUser, ip: string) {
    const findUser = await this.user.findOneBy({ userId: data.userId })

    findUser.lastLoginIp = ip
    findUser.lastLoginTime = createDate()

    await this.user.save(findUser)

    return ResultData.ok({
      data: {
        userAvatar: findUser.userAvatar,
        userNickname: findUser.userNickname
      },
    })
  }

  /**
   * 用于生成字母验证码并存在redis
   * @param murmur 浏览器指纹
   * @returns base64字母验证码的图片
   */
  async generateCode(murmur: string) {
    const { code, image } = generateCanvas()
    await this._redis.set(RedisKeyMap.userCode(murmur), code.toLowerCase(), 60)

    return image
  }

}
